import { NavBar, InfiniteScroll, Toast, Popup } from 'antd-mobile'
import CommentItem from './components/CommentItem'
import CommentInput from './components/CommentInput'
import CommentFooter from './components/CommentFooter'
import NoneComment from '@/components/NoneComment'
import Reply from './components/Reply'

import { useHistory, useParams } from 'react-router-dom'
import { useEffect, useRef, useState } from 'react'
import { useDispatch } from 'react-redux'
import { Dispatch } from 'redux'
import { useInitialState } from '@/utils/use-initial-state'
import {
  collectedArticle,
  followAuthor,
  getArticleById,
  getArticleComments,
  likeArticle,
  getArticleCommentsFirst,
  addArticleComment,
  articleCommentThumbUp,
  updataCommentCount,
} from '@/store/actions/article'

import throttle from 'lodash/throttle'

import ContentLoader from 'react-content-loader'

import highlight from 'highlight.js'
import 'highlight.js/styles/github-dark-dimmed.css'

import DOMPurify from 'dompurify'

import { ArtComment } from '@/types/data'

import classNames from 'classnames'
import { Icon } from '@/components/Icon'
import styles from './index.module.scss'

const NAV_BAR_HEIGHT = 45

enum CommentType {
  Article = 'a',
  Comment = 'c',
}

type CommentReply = {
  visible: boolean
  commentItem: ArtComment
}

const Article = () => {
  const dispatch = useDispatch<Dispatch<any>>()
  const history = useHistory()
  const params = useParams<{ id: string }>()
  const [loading, setLoading] = useState(true)
  const [isShowAuthor, setIsShowAuthor] = useState(false)
  const [showArticleComment, setShowArticleComment] = useState(false)
  const [showReply, setShowReply] = useState<CommentReply>({
    visible: false,
    commentItem: {} as ArtComment,
  })
  const wrapperRef = useRef<HTMLDivElement>(null)
  const authorRef = useRef<HTMLDivElement>(null)
  const isShowComment = useRef(false)
  const commentRef = useRef<HTMLDivElement>(null)

  const { detail, comments } = useInitialState(
    () => getArticleById(params.id),
    'article',
    () => setLoading(false)
  )

  useEffect(() => {
    const dgHtmlDOM = document.querySelector('dg-html')

    const codes = dgHtmlDOM?.querySelectorAll<HTMLElement>('pre code')
    if (codes && codes.length > 0) {
      codes.forEach((el) => {
        highlight.highlightElement(el)
      })
      return
    }

    const pres = dgHtmlDOM?.querySelectorAll('pre')
    if (pres && pres.length > 0) {
      pres.forEach((el) => {
        highlight.highlightElement(el)
      })
    }
  }, [detail])

  useEffect(() => {
    const wrapper = wrapperRef.current
    if (!wrapper) return
    const author = authorRef.current
    if (!author) return

    const onScroll = throttle(() => {
      const { top, height } = author.getBoundingClientRect()
      if (top <= NAV_BAR_HEIGHT - height) {
        setIsShowAuthor(true)
      } else {
        setIsShowAuthor(false)
      }
    }, 100)
    wrapper.addEventListener('scroll', onScroll)

    return () => {
      wrapper.removeEventListener('scroll', onScroll)
    }
  }, [loading])

  // 这里考虑到第一次 hasMore为false加载更多数据时会出现问题，所以自己手动发请求
  // 这种情况会出现框架的热重载（代码没有错误，只是框架的特点）：会在保存之后不刷新页面的情况下更新，会出现重复追加的情况，但代码没错误
  useEffect(() => {
    dispatch(getArticleCommentsFirst(CommentType.Article, params.id, null))
  }, [dispatch, params.id])

  const showComment = () => {
    const wrapper = wrapperRef.current
    if (!wrapper) return
    const comment = commentRef.current
    if (!comment) return

    const commentTop = comment.getBoundingClientRect().top
    if (!isShowComment.current) {
      wrapper.scrollTo({
        top: commentTop - NAV_BAR_HEIGHT + wrapper.scrollTop,
        behavior: 'auto',
      })

      isShowComment.current = true
    } else {
      wrapper.scrollTo(0, 0)

      isShowComment.current = false
    }
  }

  const onFollowAuthor = async () => {
    await dispatch(followAuthor(aut_id, is_followed))

    Toast.show({
      content: is_followed ? '取消关注' : '已关注',
      duration: 800,
    })
  }

  const onCollected = async () => {
    await dispatch(collectedArticle(art_id, is_collected))

    Toast.show({
      content: is_collected ? '取消收藏' : '已收藏',
      duration: 800,
    })
  }

  const onLike = async () => {
    await dispatch(likeArticle(art_id, attitude))

    Toast.show({
      content: attitude === 1 ? '取消点赞' : '已点赞',
      duration: 800,
    })
  }

  const onArticleCommentHide = () => setShowArticleComment(false)

  const onAddComment = async (value: string) => {
    await dispatch(addArticleComment(art_id, value))

    onArticleCommentHide()
  }

  const onThumbUp = (com_id: string, is_liking: boolean) => {
    dispatch(articleCommentThumbUp(com_id, is_liking))
  }

  const onReplyHide = (commentId: string, total: number) => {
    dispatch(updataCommentCount(commentId, total))

    setShowReply({
      ...showReply,
      visible: false,
    })
  }

  const {
    art_id,
    aut_id,
    attitude,
    content,
    is_followed,
    is_collected,
    title,
    pubdate,
    aut_name,
    aut_photo,
    comm_count,
    like_count,
    read_count,
  } = detail

  const loadMoreComments = async () => {
    await dispatch(getArticleComments(CommentType.Article, params.id, last_id))
  }

  const { end_id, last_id } = comments

  const hasMore = end_id !== last_id

  if (loading) {
    return (
      // 根据当前页面结构，设计好的 loading 效果
      <ContentLoader
        speed={2}
        width={375}
        height={230}
        viewBox="0 0 375 230"
        backgroundColor="#f3f3f3"
        foregroundColor="#ecebeb"
      >
        <rect x="16" y="8" rx="3" ry="3" width="340" height="10" />
        <rect x="16" y="26" rx="0" ry="0" width="70" height="6" />
        <rect x="96" y="26" rx="0" ry="0" width="50" height="6" />
        <rect x="156" y="26" rx="0" ry="0" width="50" height="6" />
        <circle cx="33" cy="69" r="17" />
        <rect x="60" y="65" rx="0" ry="0" width="45" height="6" />
        <rect x="304" y="65" rx="0" ry="0" width="52" height="6" />
        <rect x="16" y="114" rx="0" ry="0" width="340" height="15" />
        <rect x="263" y="208" rx="0" ry="0" width="94" height="19" />
        <rect x="16" y="141" rx="0" ry="0" width="340" height="15" />
        <rect x="16" y="166" rx="0" ry="0" width="340" height="15" />
      </ContentLoader>
    )
  }

  const renderArticle = () => {
    // 文章详情
    return (
      <div className="wrapper" ref={wrapperRef}>
        <div className="article-wrapper">
          <div className="header">
            <h1 className="title">{title}</h1>

            <div className="info">
              <span>{pubdate}</span>
              <span>{read_count} 阅读</span>
              <span>{comm_count} 评论</span>
            </div>

            <div className="author" ref={authorRef}>
              <img
                src={
                  aut_photo || 'http://geek.itheima.net/images/user_head.jpg'
                }
                alt=""
              />
              <span className="name">{aut_name}</span>
              <span
                onClick={onFollowAuthor}
                className={classNames('follow', is_followed ? 'followed' : '')}
              >
                {is_followed ? '已关注' : '关注'}
              </span>
            </div>
          </div>

          <div className="content">
            <div
              className="content-html dg-html"
              dangerouslySetInnerHTML={{
                __html: DOMPurify.sanitize(content),
              }}
            />
            <div className="date">发布文章时间：{pubdate}</div>
          </div>
        </div>

        <div className="comment" ref={commentRef}>
          <div className="comment-header">
            <span>全部评论（{comm_count}）</span>
            <span>{like_count} 点赞</span>
          </div>
          {comments.results.length === 0 ? (
            <NoneComment />
          ) : (
            <div className="comment-list">
              {comments.results.map((item) => (
                <CommentItem
                  key={item.com_id}
                  {...item}
                  onThumbUp={() => onThumbUp(item.com_id, item.is_liking)}
                  onReplyShow={() =>
                    setShowReply({
                      visible: true,
                      commentItem: item,
                    })
                  }
                />
              ))}

              <InfiniteScroll hasMore={hasMore} loadMore={loadMoreComments} />
            </div>
          )}
        </div>
      </div>
    )
  }

  const renderArticleComment = () => {
    return (
      <Popup
        bodyStyle={{
          height: '100%',
        }}
        position="bottom"
        visible={showArticleComment}
        destroyOnClose
      >
        <CommentInput
          onClose={onArticleCommentHide}
          onAddComment={onAddComment}
        ></CommentInput>
      </Popup>
    )
  }

  const renderCommentReply = () => {
    return (
      <Popup
        bodyStyle={{
          width: '100%',
        }}
        position="right"
        visible={showReply.visible}
        destroyOnClose
      >
        <Reply
          onClose={onReplyHide}
          commentItem={showReply.commentItem}
          onReplyThumbUp={onThumbUp}
          articleId={params.id}
        ></Reply>
      </Popup>
    )
  }

  return (
    <div className={styles.root}>
      <div className="root-wrapper">
        <NavBar
          onBack={() => history.go(-1)}
          right={
            <span>
              <Icon type="icongengduo" />
            </span>
          }
        >
          {isShowAuthor && (
            <div className="nav-author">
              <img
                src={
                  aut_photo || 'http://geek.itheima.net/images/user_head.jpg'
                }
                alt=""
              />
              <span className="name">{aut_name}</span>
              <span
                onClick={onFollowAuthor}
                className={classNames('follow', is_followed ? 'followed' : '')}
              >
                {is_followed ? '已关注' : '关注'}
              </span>
            </div>
          )}
        </NavBar>
        {/* 文章详情和评论 */}
        {renderArticle()}

        {/* 底部评论栏 */}
        <CommentFooter
          comm_count={comm_count}
          showComment={showComment}
          is_collected={is_collected}
          onCollected={onCollected}
          attitude={attitude}
          onLike={onLike}
          onShowArticleComment={() => setShowArticleComment(true)}
        />
      </div>

      {renderArticleComment()}

      {renderCommentReply()}
    </div>
  )
}

export default Article
